﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace PlanetViewer
{
    static class util
    {
        public static float[] CosineInterp(float Y1, float Y2, int dX) //Interpolates between Y1 and Y2 over dX steps, using a cos(0-PI) profile
        {
            float[] interp = new float[dX - 1];

            for (int c = 1; c < dX; c++)
            {
                float h = 0.5f * ((Y1 - Y2) * (float)Math.Cos(c * MathHelper.Pi / dX) + Y1 + Y2);

                interp[c - 1] = h;
            }

            return interp;
        }

        public static float[] HalfSineInterp(float Y1, float Y2, int dX) //Interpolates between Y1 and Y2 over dX steps, using a sin(0-PI/2) profile
        {
            float[] interp = new float[dX - 1];

            for (int c = 1; c < dX; c++)
            {
                float h = (Y2 - Y1) * (float)Math.Sin(c * 0.5f * MathHelper.Pi / dX) + Y1;

                interp[c - 1] = h;
            }

            return interp;
        }

        public static float[] HalfCosineInterp(float Y1, float Y2, int dX) //Interpolates between Y1 and Y2 over dX steps, using a cos(0-PI/2) profile
        {
            float[] interp = new float[dX - 1];

            for (int c = 1; c < dX; c++)
            {
                float h = (Y1 - Y2) * (float)Math.Cos(c * 0.5f * MathHelper.Pi / dX) + Y2;

                interp[c - 1] = h;
            }

            return interp;
        }

        public static int[][] CreateIndexMatrix(int nSpines, int nLayers)
        {
            int[][] indMat = new int[nSpines + 1][];

            for (int i = 0; i <= nSpines; i++)
            {
                int nRows = 1 + nLayers;

                int[] Spine = new int[nRows];

                for (int n = 0; n < nRows; n++)
                {
                    Spine[n] = n * (nSpines + 1) + i;
                }

                indMat[i] = Spine;
            }

            return indMat;
        }

        public static int[] IndicesFromVertices(VertexPositionColor[] vertices, int nLayers = 1)
        {
            int nSpines = (vertices.Length - (1 + nLayers)) / (1 + nLayers);
            int nTris = 2 * nSpines * nLayers;
            int nIndices = 3 * nTris;

            int[][] indMat = CreateIndexMatrix(nSpines, nLayers);

            int[] Indices = new int[nIndices];

            for (int L = 0; L < nLayers; L++)
            {
                for (int Sp = 0; Sp < nSpines; Sp++)
                {
                    int SpNext = Sp + 1;
                    int Quad = 6 * (Sp + L * nSpines);

                    Indices[Quad] = indMat[Sp][L];
                    Indices[Quad + 1] = indMat[SpNext][L];
                    Indices[Quad + 2] = indMat[Sp][L + 1];

                    Indices[Quad + 3] = indMat[SpNext][L];
                    Indices[Quad + 4] = indMat[Sp][L + 1];
                    Indices[Quad + 5] = indMat[SpNext][L + 1];
                }
            }

            return Indices;
        }

        public static int[] CreateLayeredIndexArray(int nSpines, int nLayers = 1)
        {
            int nVerts = (1 + nLayers) * (nSpines + 1);
            int nTris = nLayers * 2 * nSpines;
            int nIndices = 3 * nTris;

            int[][] indMat = CreateIndexMatrix(nSpines, nLayers);

            int[] Indices = new int[nIndices];

            for (int L = 0; L < nLayers; L++)
            {
                for (int Sp = 0; Sp < nSpines; Sp++)
                {
                    int SpNext = Sp + 1;
                    int Quad = 6 * (Sp + L * nSpines);

                    Indices[Quad] = indMat[Sp][L];
                    Indices[Quad + 1] = indMat[SpNext][L];
                    Indices[Quad + 2] = indMat[Sp][L + 1];

                    Indices[Quad + 3] = indMat[SpNext][L];
                    Indices[Quad + 4] = indMat[Sp][L + 1];
                    Indices[Quad + 5] = indMat[SpNext][L + 1];
                }
            }

            return Indices;
        }

        public static VertexPositionColor CreateRotatedVertex(float radius, float angle)
        {
            VertexPositionColor V = new VertexPositionColor();

            float x = radius * (float)Math.Cos(angle);
            float y = radius * (float)Math.Sin(angle);

            V.Position = new Vector3(x, y, 0);

            return V;
        }

        public static VertexPositionColor RotateVertex(VertexPositionColor V, float angle)
        {
            float x = V.Position.X * (float)Math.Cos(angle);
            float y = V.Position.X * (float)Math.Sin(angle);

            V.Position = new Vector3(x, y, 0);

            return V;
        }

        public static VertexPositionColor[] CombineVertexArrays(VertexPositionColor[] array1, VertexPositionColor[] array2)
        {
            int iCount = array1.Length + array2.Length;
            VertexPositionColor[] newArray = new VertexPositionColor[iCount];

            array1.CopyTo(newArray, 0);
            array2.CopyTo(newArray, array1.Length);

            return newArray;
        }

        public static int[] CombineIndexArrays(int[] array1, int[] array2, int offset)
        {
            int iCount = array1.Length + array2.Length;
            int[] newArray = new int[iCount];

            array1.CopyTo(newArray, 0);
            
            for (int i = 0; i < array2.Length; i++) array2[i] += offset;
            array2.CopyTo(newArray, array1.Length);

            return newArray;
        }

        public static Color ColorInterp(Color color1, Color color2, float value = 0.5f)
        {
            int R = color1.R + (int)(value * (color2.R - color1.R));
            int G = color1.G + (int)(value * (color2.G - color1.G));
            int B = color1.B + (int)(value * (color2.B - color1.B));

            Color interp = new Color(R, G, B);

            return interp;
        }

        public static int Modulo(int input, int modulus)
        {
            while (input < 0) input += modulus;

            while (input >= modulus) input -= modulus;

            return input;
        }
    }
}
